﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class CharacterController : MonoBehaviour {

	[SerializeField] private float m_JumpForce = 400f;
	[SerializeField] private float m_WalkSpeed = 40f;
	[SerializeField] private float m_RunSpeed = 80f;
	//[SerializeField] private float m_MovementSmoothing = .3f;

	[SerializeField] private LayerMask m_GroundLayerMasks;
	[SerializeField] private Transform m_GroundCheck;
	[Range(0f, .5f)] [SerializeField] private float m_GroundCheckRadius = .2f;
	[SerializeField] private Transform m_CrouchCheck;
	[SerializeField] private Vector2 m_CrouchCheckSize;
	[SerializeField] private LayerMask m_CrouchLayerMasks;

	public Collider2D m_EnabledCollider;
	public Collider2D m_FootCollider;
	[SerializeField] Collider2D m_CrouchCollider;

	public Rigidbody2D rb {
		get;
		set;
	}

	public bool m_AirController;
	public bool m_FacingRight {
		set;
		get;
	}
	bool m_WasCrounching;

	Vector3 velocity = Vector3.zero;

	public bool Grounded {
		get;
		set;
	}

	public bool GroundIsPlatform => groundIsPlatform;

	private bool groundIsPlatform;

	[System.Serializable]
	public class BoolEvent : UnityEvent<bool> { }

	[Header("Events")]
	[Space]
	public BoolEvent m_JumpingEvent;
	public BoolEvent m_CrounchEvent;
	public BoolEvent m_FallingEvent;

	private void Awake() {
		rb = gameObject.GetComponent<Rigidbody2D>();

		if (m_JumpingEvent == null)
			m_JumpingEvent = new BoolEvent();

		if (m_CrounchEvent == null)
			m_CrounchEvent = new BoolEvent();

		if (m_FallingEvent == null)
			m_FallingEvent = new BoolEvent();

	}

	private void Start() {

		m_FacingRight = (transform.localScale.x > 0);

	}

	private void FixedUpdate() {
		bool wasGrounded = Grounded;
		Grounded = false;
		//ground 判断
		Collider2D[] collider2Ds = Physics2D.OverlapCircleAll(m_GroundCheck.position, m_GroundCheckRadius, m_GroundLayerMasks);
		foreach (Collider2D cd in collider2Ds)
		{
			if (cd.gameObject.tag != gameObject.tag) {
				Grounded = true;
				if (!wasGrounded) {
					m_JumpingEvent.Invoke(false);
					m_FallingEvent.Invoke(false);
					Grounded = true;
				}
			}
			groundIsPlatform = cd.CompareTag(TagAndLayersConfigs.Tag.Platform);
		}

	}

	public void Move(float move, bool run, bool crouch, bool jump, bool jumpFix, float pull, bool climb) {

		if (!Grounded && !climb && !jumpFix) {
			m_FallingEvent.Invoke(true);
		} else {
			m_FallingEvent.Invoke(false);
		}

		if ((!Grounded && crouch) || (climb && crouch) || groundIsPlatform)
			crouch = false;

		/*
		 *	crouch 行为判断
		 *	1. 如果顶上有强不允许跳跃
		 *	2. 非crouch下自动进入crouch状态
		 */
		if (!crouch && m_CrouchCheck != null) {
			if (Physics2D.OverlapBox(new Vector2(m_CrouchCheck.position.x, m_CrouchCheck.position.y) + m_CrouchCheckSize / 2, m_CrouchCheckSize, 0, m_CrouchLayerMasks)) {
				jump = false;
				m_JumpingEvent.Invoke(false);
				crouch = true;
			}
		}

		if (Grounded || m_AirController) {

			float velocityX = run && !crouch ? move * m_RunSpeed * Time.fixedDeltaTime * 10 : move * m_WalkSpeed * Time.fixedDeltaTime * 10;
			velocityX *= 1 - pull;
			if (crouch) {
				if (!m_WasCrounching) {
					m_WasCrounching = true;
					m_CrounchEvent.Invoke(true);
				}

				velocityX *= .8f;
				if (m_EnabledCollider != null) {
					CrouchWithCollider(true);
				}
			} else {

				if (m_EnabledCollider != null) {
					CrouchWithCollider(false);
				}

				if (m_WasCrounching) {
					m_WasCrounching = false;
					m_CrounchEvent.Invoke(false);
				}

			}

			Vector3 forwardVelocity = new Vector2(velocityX, rb.velocity.y);
			//rb.velocity = Vector3.SmoothDamp(rb.velocity, forwardVelocity, ref velocity,m_MovementSmoothing);
			if (rb.bodyType == RigidbodyType2D.Dynamic)
				rb.velocity = forwardVelocity;

			if (!m_WasCrounching && pull <= 0 && !jumpFix) {

				if (move > 0 && !m_FacingRight) {
					Flip();
				} else if (move < 0 && m_FacingRight) {
					Flip();
				}
			}

		}

		if (jump && Grounded) {
			m_JumpingEvent.Invoke(true);
			// rb.AddForce(Vector3.up * m_JumpForce + (move != 0 ? Vector3.right * .2f * m_JumpForce * transform.localScale.x : Vector3.zero));

			//if (groundIsPlatform)
			//{ 
			//	rb.AddForce(Vector3.up * m_JumpForce / 3 * 2);
			//}
			//else
			//{
				rb.AddForce(Vector3.up * m_JumpForce);
			//}
		}

	}
	/// <summary>
	///  转向碰撞盒变化
	/// </summary>
	/// <param name="courch"></param>
	void CrouchWithCollider(bool courch) {
		if (courch) {
			m_CrouchCollider.enabled = true;
			m_EnabledCollider.enabled = false;
			m_FootCollider.enabled = false;
		} else {
			m_CrouchCollider.enabled = false;
			m_EnabledCollider.enabled = true;
			m_FootCollider.enabled = true;
		}
	}
	/// <summary>
	///  转向
	/// </summary>
	void Flip() {

		Vector3 scale = transform.localScale;
		scale.x *= -1;
		transform.localScale = scale;

		m_FacingRight = !m_FacingRight;
		FlipWithCrouchCheck();

	}

	public void Flip(float move) {

		if (move > 0 && !m_FacingRight) {
			Flip();
		} else if (move < 0 && m_FacingRight) {
			Flip();
		}
	}

	/// <summary>
	/// 调整CrouchCheck.x的位置，确保刚好位于碰撞盒(m_EnabledCollider)边缘
	/// </summary>
	void FlipWithCrouchCheck() {
		if (m_EnabledCollider == null || m_GroundCheck == null)
			return;
		CapsuleCollider2D target = (CapsuleCollider2D)m_EnabledCollider;
		float x;
		if (m_FacingRight) {
			x = target.bounds.center.x + target.offset.x + target.size.x / 2;
		} else {
			x = target.bounds.center.x - target.bounds.extents.x / 2 - target.offset.x - target.size.x / 2;
		}
		m_CrouchCheck.position = new Vector2(x, m_CrouchCheck.position.y);

	}

	private void OnDrawGizmos() {

		//地面 框
		Gizmos.DrawWireSphere(m_GroundCheck.position, m_GroundCheckRadius);

		//趴行 框
		if (m_CrouchCheck)
			Gizmos.DrawWireCube(new Vector2(m_CrouchCheck.position.x, m_CrouchCheck.position.y) + m_CrouchCheckSize / 2, m_CrouchCheckSize);

	}

}
